#!/usr/bin/env bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source $DIR/../../lib/shell/common.sh
source $DIR/../../lib/shell/env.sh
source $DIR/network_stress.sh

function run_offload() {
    echo "start feature offload"

    [ -n "$INTERFACES" ] || { echo "no interfaces to be tested";return 1; }
    netdev=$INTERFACES

    feature_short_name=(rx tx sg tso ufo gso gro lro rxvlan txvlan ntuple rxhash)
    feature_long_name=(rx-checksumming \
                    tx-checksumming \
                    scatter-gather \
                    tcp-segmentation-offload \
                    udp-fragmentation-offload \
                    generic-segmentation-offload \
                    generic-receive-offload \
                    large-receive-offload \
                    rx-vlan-offload \
                    tx-vlan-offload \
                    ntuple-filters \
                    receive-hashing \
    )

    # start stress 
    [ -z "$LTS_IPADDRESS" ] && { echo "Error: LTS IP are required, but none are given";exit 1; }
    lts_ip=$(echo $LTS_IPADDRESS | awk '{print $1}')

    server_run
    [ $? -ne 0 ] && return 1

    if ps -ef|grep iperf3|grep -w $IPERF3_PORT >/dev/null 2>&1;then
        kill -9 `ps -ef|grep iperf3|grep -w $IPERF3_PORT|awk '{print $2}'`
    fi
    IPERF3_LOG="${IPERF3_LOG_PATH}/feature_offload.iperf3"
    client_run
    sleep 5

    for n in $netdev
    do
        echo testing nic $n

        available_features=""
        available_features_long=""
        feature_availability $n || return 1

        for f in $available_features
        do
            echo test feature $f
            offload_one $n $f || return 1
            check_status $n || return 1
            echo
        done
    done

	# end stress
    wait
    server_kill || return 1

    check_iperf3_stress_results && return 0 || return 1

}

function feature_availability(){
    local dev=$1
    local it=0
    for ft in ${feature_short_name[@]}
    do
        # echo $feature
        local ft_long=${feature_long_name[$it]}
        if ethtool -k $dev 2>/dev/null | grep ^$ft_long | grep -q "off$"; then
            ethtool -K $dev $ft on >/dev/null 2>&1
            sleep 1
            if ethtool -k $dev 2>/dev/null | grep ^$ft_long | grep -q "on$"; then
                available_features="$available_features $ft:$ft_long"
            fi
            # resume
            ethtool -K $dev $ft off >/dev/null 2>&1 || return 1
        elif ethtool -k $dev 2>/dev/null | grep ^$ft_long | grep -q "on$"; then
            available_features="$available_features $ft:$ft_long"
        fi
        ((it++))
    done
    return 0
}

function client_run() {
    echo "start client connect"
    client_cmd="iperf3 -t $IPERF3_RUNTIME -i $IPERF3_INTERVAL -P $IPERF3_PROCESS_NUM -f g -c $lts_ip"
    run_cmd "$client_cmd" "$IPERF3_LOG" &
}

function server_kill() {
    server_down="kill -9 \`pidof iperf3\` &>/dev/null"
    $ESSH $lts_ip $server_down || return 1
    return 0
}

function server_run() {
    echo "start server listen"
    server_kill
    server_cmd="iperf3 -sD"
    $ESSH $lts_ip $server_cmd &
    if [ $? -eq 0 ]; then
        echo "server listen success"
        sleep 3
        return 0
    else
        echo "server listen failed"
        return 1
    fi
}

function offload_one(){
    local dev=$1
    local feature=$(echo $2 | awk -F: '{print $1}')
    local long_name=$(echo $2 | awk -F: '{print $2}')
	
    local output=$(ethtool -k $dev 2>/dev/null | grep ^$long_name)
    # if this feature is on, turn it off and then resume the status
    if echo $output | grep -q "on$"; then
        echo $output, try to turn it off...
        turn_off=$(ethtool -K $dev $feature off 2>/dev/null)
        sleep 1

        # check status
        ethtool -k $dev 2>/dev/null | grep ^$long_name | grep -q "off$"
        [ $? -eq 0 ] || { echo "cannot turn it off: $feature";return 0; }
		
        turn_on=$(ethtool -K $dev $feature on 2>/dev/null)
        sleep 1

        ethtool -k $dev 2>/dev/null | grep ^$long_name | grep -q "on$"
        [ $? -eq 0 ] || { echo -e "cannot resume status of $feature";return 1; }
    elif echo $output | grep -q "off$"; then
        # if this one is off
        echo $output, try to turn it on...
        turn_on=$(ethtool -K $dev $feature on 2>/dev/null)
        sleep 1

        ethtool -k $dev 2>/dev/null | grep ^$long_name | grep -q "on$"
        [ $? -eq 0 ] || { echo "cannot turn it on: $feature";return 0; }
		
        turn_off=$(ethtool -K $dev $feature off 2>/dev/null)
        sleep 1

        ethtool -k $dev 2>/dev/null | grep ^$long_name | grep -q "off$"
        [ $? -eq 0 ] || { echo -e "cannot resume status of $feature";return 1; }
    fi

    return 0
}

function check_status() {
    local dev=$1
    if ip link show $dev | grep -q "UP"; then
        return 0
    fi
    echo "$dev is DOWN"
    return 1
}


# # # # # # # # main # # # # # # # #
print_test_info "Network"
bash ../../../utils/sshconf.sh setup
trap "bash ../../../utils/sshconf.sh restore" EXIT
stress_network_env 5 $RUNTIME
run_offload && test_pass || test_fail